home *** CD-ROM | disk | FTP | other *** search
/ Floppyshop 2 / Floppyshop - 2.zip / Floppyshop - 2.iso / art&graf.ix / art-3485 / art-3871 / mdl10 / flicker.c < prev    next >
C/C++ Source or Header  |  1993-06-06  |  24KB  |  1,132 lines

  1. /*
  2.  *    flicker.c - display grayscale image with flicker mode
  3.  *
  4.  *    modified for dl/gl files. pimg points to all the raw images and
  5.  *    nframes is the number of frames. no histogram stuff at all. handles
  6.  *    dl commands (which is a list of frame indices in order).
  7.  *
  8.  *    note: I16 is 16 bit integer so we don't care what an "int" is
  9.  *    external to this routine. when u see 96000, it is really
  10.  *    48000 * sizeof(I16). most things here are actually tuned to 16 bit
  11.  *    ints.
  12.  *
  13.  *    now ansi for gcc. -mshort not needed.
  14.  *
  15.  *    compilation control:
  16.  *        NEW_RANDOM    def to use new random noise code
  17.  *        NO_INVERT    def to invert pixel intensities (normally
  18.  *                undefined)
  19.  */
  20.  
  21. typedef short I16;
  22. typedef unsigned short UI16;
  23.  
  24. #ifndef lint
  25. static char *rcsid = "$Id: flicker.c,v 1.3 1991/07/24 17:13:48 rosenkra Exp $";
  26. #endif
  27.  
  28. /*
  29.  * $Log: flicker.c,v $
  30.  * Revision 1.3  1991/07/24  17:13:48  rosenkra
  31.  * now RCS. fix flicker for SimpConv2Gray so image is not so dark. also
  32.  * make sure last work in each pixel row gets dumped to screen when
  33.  * using SimpConv2Gray (e.g. during cut or zoom).
  34.  *
  35.  * Revision 1.2  1991/07/16  23:24:48  rosenkra
  36.  * released june 91 to usenet. first RCS revision.
  37.  *
  38.  */
  39.  
  40. /*
  41.  *    this is for screen-switching on mono to simulate grayscale. it
  42.  *    uses a combination of floyd-steinberg and simulate "planes" which
  43.  *    get displayed each vblank. the image it works from should be
  44.  *    grayscale, i.e. each pixel is represented by an 8-bit (0 to 255)
  45.  *    intensity. since GIF images come with a color table, it is first
  46.  *    required to map each GIF pixel to the color table which has been
  47.  *    first changed to grayscale, either by averaging the rgb values
  48.  *    or by using the NTSC intensity equation.
  49.  *
  50.  *    note that i think the f-s algorithm employed here sweeps each row
  51.  *    left to right rather than alternating directions. that is why there
  52.  *    is spurious info in areas otherwise supposed to be white.
  53.  *
  54.  *    also, all points where chars are used in a calculation, they MUST
  55.  *    be unsigned.
  56.  *
  57.  *    return ptr to screens.
  58.  */
  59.  
  60. /* written by Klaus Pedersen (micro@imada.dk) */
  61. /* modified by Bill Rosenkranz (rosenkra@convex.com) */
  62.  
  63. #include <stdio.h>
  64. #include <types.h>
  65. #include <stdlib.h>    /* for malloc */
  66. #include <string.h>    /* for bzero */
  67. #include <osbind.h>
  68.  
  69.  
  70. #define LEVELS        4
  71. #define NUMERRS        1024
  72. #define SCRNSPACE    48256L        /* now per frame */
  73. #define MAXFRAMES    25        /* 25 needs 2.4 MB (96000B/frame) */
  74.  
  75.  
  76. /*
  77.  *    globals.
  78.  *
  79.  *    these are the thresholds for quantizing. 0,85,170,255 seem best
  80.  */
  81. static I16    _Levels[LEVELS]     = {  0,  85, 170, 255};
  82. static I16    _SimpLevels[LEVELS] = {  0, 255};
  83.  
  84. static int    _Show;            /* print progress to stdout if !=0 */
  85. static int    _Delay;            /* ms delay between frames (if +ve) */
  86. static I16    _Nframes;        /* number of frames in raster */
  87. static I16    _Ncommands;        /* number of commands */
  88. static I16    _Width;            /* image size */
  89. static I16    _Hight;
  90. static I16         _Beta;            /* for the Laplace filter */
  91. static I16         _MaxRandom;        /* for adding random noise */
  92. static I16     *_Err1,            /* the error propagation arrays */
  93.            *_Err2;
  94. static I16         _Err1Array[NUMERRS],
  95.             _Err2Array[NUMERRS];
  96.  
  97. static I16     *_Scrn,            /* we malloc space here */
  98.            *_Scrn1[MAXFRAMES],
  99.            *_Scrn2[MAXFRAMES],
  100.            *_Scrn3[MAXFRAMES];
  101.  
  102.  
  103.  
  104. /*
  105.  *    local functions
  106.  */
  107. static void    _Conv2Gray (unsigned char *, int *);
  108. static void    _SimpConv2Gray (unsigned char *, int *);
  109. static I16    _GenConvPix (unsigned char *, int, int);
  110. static I16    _SimpGenConvPix (unsigned char *, int, int);
  111. static I16    _Laplace (unsigned char *);
  112. static void    _ClearErr (void);
  113. static I16    _Rand (I16);
  114.  
  115.  
  116.  
  117.  
  118. /*------------------------------*/
  119. /*    dl_flicker        */
  120. /*------------------------------*/
  121. int dl_flicker (unsigned char *pimg, int nframes, int width, int hight,
  122.         int beta, int maxrandom, int opt, int delay, int *cmd,
  123.         int ncommands, int show)
  124.  
  125.         /* pimg        -> raster image sequence (intensities) */
  126.         /* nframes    number of frames in pimg */
  127.         /* width    width, pixels */
  128.         /* hight    height, pixels */
  129.         /* beta        for laplace filter */
  130.         /* maxrandom    for random noise */
  131.         /* opt        0=no flicker, 1=flicker */
  132.         /* delay    ms delay between images */
  133.         /* cmd        -> commands (order to display frames) */
  134.         /* ncommands    number of commands (total frames in loop) */
  135.         /* show        print info to stdout if != 0 */
  136. {
  137.  
  138. /*
  139.  *    this is the main entry point. complete grayscale raster image
  140.  *    comes from pimg with height and width specified. if beta != 0,
  141.  *    do Laplace filter with that beta. if maxrandom != 0, add some
  142.  *    random noise with that value (see below).
  143.  *
  144.  *    pimg contains each basic frame in succession.
  145.  *
  146.  *    dl commands are used. do this in loop showing the basic screens
  147.  *    by indexing into _Scrn* as _Scrn*[cmd[i]].
  148.  *
  149.  *    return 0 if ok. 1 if error.
  150.  */
  151.  
  152.  
  153.  
  154.     /*
  155.      *   set our globals
  156.      */
  157.     _Show      =       show;
  158.     _Nframes   = (I16) nframes;    /* number of frames in raster */
  159.     _Ncommands = (I16) ncommands;    /* number of commands in animation */
  160.     _Delay     =       delay;    /* ms delay between frames */
  161.     _Hight     = (I16) hight;    /* its height... */
  162.     _Width     = (I16) width;    /* ...and width */
  163.     _Beta      = (I16) beta;    /* Laplace filter coefficient */
  164.                     /* 1=0.25, 2=0.50, 3=0.75... (Try 4) */
  165.     _MaxRandom = (I16) maxrandom;    /* amount of random noise, 0-255 */
  166.                     /* for 0% to 100% noise. (Try 10) */
  167.  
  168.  
  169.  
  170.     /*
  171.      *   check nframes.
  172.      */
  173.     if (_Show)
  174.         printf ("flicker: num frames = %d, max allowed = %d\n",
  175.             _Nframes, MAXFRAMES);
  176.     if (_Nframes > MAXFRAMES)
  177.         _Nframes = MAXFRAMES;
  178.  
  179.  
  180.  
  181.     /*
  182.      *   allocate space for all screens. note that sizeof(I16) is 2.
  183.      */
  184.     if (opt)
  185.     {
  186.         if (_Show)
  187.             printf ("flicker: allocating memory, flicker mode (%ld bytes)\n",
  188.                 96000L * (long)_Nframes);
  189.         _Scrn = (I16 *) malloc (96000 * (size_t) _Nframes + 256);
  190.     }
  191.     else
  192.     {
  193.         if (_Show)
  194.             printf ("flicker: allocating memory, not flicker (%ld bytes)\n",
  195.                 32000L * (long)_Nframes);
  196.         _Scrn = (I16 *) malloc (32000 * (size_t) _Nframes + 256);
  197.     }
  198.     if (_Scrn == (I16 *) NULL)
  199.     {
  200.         if (_Show)
  201.             printf ("flicker: memory allocation failed\n");
  202.         return (1);
  203.     }
  204.  
  205.  
  206.  
  207.     /*
  208.      *   make sure screen is aligned on 256-byte boundary.
  209.      */
  210.     _Scrn = (I16 *) (((long) _Scrn + 256L) & 0xFFFFFF00L);
  211.  
  212.  
  213.  
  214.     /*
  215.      *   clear screens. this may not have to be done if malloc clears
  216.      *   or if the dithering touches everything
  217.      */
  218.     if (_Show)
  219.         printf ("flicker: clearing memory...\n");
  220.     if (opt)
  221.         bzero (_Scrn, (size_t) (96000 * _Nframes));
  222.     else
  223.         bzero (_Scrn, (size_t) (32000 * _Nframes));
  224.  
  225.  
  226.  
  227.     /*
  228.      *   do it!
  229.      */
  230.     if (opt)
  231.         _Conv2Gray (pimg, cmd);
  232.     else
  233.         _SimpConv2Gray (pimg, cmd);
  234.  
  235.  
  236.     return (0);
  237. }
  238.  
  239.  
  240.  
  241.  
  242. /*------------------------------*/
  243. /*    _Conv2Gray        */
  244. /*------------------------------*/
  245. static void _Conv2Gray (unsigned char *pic, int *cmd)
  246. {
  247.     unsigned char           *ppic;
  248.     register int        i;
  249.     int            j;
  250.     register I16            x;
  251.     I16                y;
  252.     I16            w;
  253.     I16            h;
  254.     register long            yoffset;
  255.     I16               *TmpErr;
  256.     register I16            q;
  257.     I16                rover1;
  258.     I16                rover2;
  259.     register UI16        pix;
  260.     unsigned char           *p;
  261.     char               *old1;
  262.     char               *old2;
  263.     int            rpt;
  264.     int            done;
  265.  
  266.  
  267.  
  268.  
  269.     /*
  270.      *   number of times to repeat inner display loop showing a single
  271.      *   frame. this is to deal with different frame rates. 40 ms for
  272.      *   three Setscreen/Vsync is about right on 8MHz ST...
  273.      */
  274.     rpt = _Delay / 40;
  275.  
  276.  
  277.  
  278.     /*
  279.      *   save old screen info
  280.      */
  281.     old1  = (char *) Logbase ();
  282.     old2  = (char *) Physbase ();
  283.  
  284.  
  285.  
  286.     /*
  287.      *   clear...
  288.      */
  289.     if (_Show)
  290.         printf ("flicker: clear screen...\n");
  291.     bzero (old1, (size_t) 32000);
  292.     bzero (old2, (size_t) 32000);
  293.  
  294.  
  295.  
  296.     /*
  297.      *   we will set physbase to our buffer and _Scrn1[0] points to it.
  298.      *   set the other screen pointers. _Scrn is a buffer large enuf
  299.      *   to hold all 3 screens for every frame. it would obviously be
  300.      *   more efficient to blit the images rather than store the entire
  301.      *   screen if the image is smaller than the entire screen.
  302.      */
  303.     _Scrn1[0] = _Scrn;
  304.     _Scrn2[0] = _Scrn1[0] + 16000L;
  305.     _Scrn3[0] = _Scrn2[0] + 16000L;
  306.     for (i = 1; i < _Nframes; i++)
  307.     {
  308.         _Scrn1[i] = _Scrn3[i-1] + 16000L;
  309.         _Scrn2[i] = _Scrn1[i]   + 16000L;
  310.         _Scrn3[i] = _Scrn2[i]   + 16000L;
  311.     }
  312.  
  313.  
  314.  
  315.     /*
  316.      *   we have to dither each frame so be patient...
  317.      */
  318.     for (ppic = pic, i = 0; i < _Nframes; i++, ppic += _Hight*_Width)
  319.     {
  320.         /*
  321.          *   monitor the progress of dithering.
  322.          *   set logbase to old physbase and physbase to first
  323.          *   screen buffer. we *should* never see logbase in the
  324.          *   displayed image since we never display logbase.
  325.          */
  326.         Setscreen (old2, (long) _Scrn1[i], -1); Vsync ();
  327.  
  328.  
  329.         /*
  330.          *   first clear the error arrays
  331.          */
  332.         _ClearErr ();
  333.  
  334.  
  335.         /*
  336.          *   initialize some things. yoffset positions us into each
  337.          *   screen which are int arrays. each scan line in the
  338.          *   screen is thus 40 words long.
  339.          */
  340.         yoffset = 0L;
  341.         rover1  = 0;
  342.         rover2  = 0;
  343.  
  344.  
  345.         /*
  346.          *   loop over all rows in image
  347.          */
  348.         h = (_Hight > 400) ? 400 : _Hight;
  349.         for (y = 1; y < h - 1; y++)
  350.         {
  351.             /*
  352.              *   set ptr to this pixel row
  353.              */
  354.             p = ppic + ((long) y * (long) _Width);
  355.  
  356.             /*
  357.              *   loop over all pixels in the row
  358.              */
  359.             w = (_Width > 640) ? 640 : _Width;
  360.             for (x = 0; x < w - 1; x++)
  361.             {
  362.                 pix = (0x8000 >> (x & 0x000f));
  363.  
  364.                 /*
  365.                  *   get new pixel value, with f-s error.
  366.                  *   this is actually an index into the
  367.                  *   _Levels array.
  368.                  */
  369.                 if (y & 1)
  370.                     q = _GenConvPix (p, (int) x, 0);
  371.                 else
  372.                     q = _GenConvPix (p, (int) x, 1);
  373.  
  374.  
  375.                 /*
  376.                  *   set screen pixels based on this index
  377.                  */
  378.                 if (q == 1)
  379.                 {
  380.                     switch (rover1)
  381.                     {
  382.                     case 0: 
  383.                     _Scrn1[i][yoffset + (x >> 4)] |= pix;
  384.                     rover1 = 1;
  385.                     rover2 = 1;
  386.                     break;
  387.                     case 1: 
  388.                     _Scrn2[i][yoffset + (x >> 4)] |= pix;
  389.                     rover1 = 2;
  390.                     rover2 = 2;
  391.                     break;
  392.                     case 2: 
  393.                     _Scrn3[i][yoffset + (x >> 4)] |= pix;
  394.                     rover1 = 0;
  395.                     rover2 = 0;
  396.                     break;
  397.                     }
  398.                 }
  399.                 else if (q == 2)
  400.                 {
  401.                     switch (rover2)
  402.                     {
  403.                     case 0: 
  404.                     _Scrn1[i][yoffset + (x >> 4)] |= pix;
  405.                     _Scrn2[i][yoffset + (x >> 4)] |= pix;
  406.                     rover2 = 1;
  407.                     rover1 = 2;
  408.                     break;
  409.                     case 1: 
  410.                     _Scrn2[i][yoffset + (x >> 4)] |= pix;
  411.                     _Scrn3[i][yoffset + (x >> 4)] |= pix;
  412.                     rover2 = 2;
  413.                     rover1 = 0;
  414.                     break;
  415.                     case 2:
  416.                     _Scrn1[i][yoffset + (x >> 4)] |= pix;
  417.                     _Scrn3[i][yoffset + (x >> 4)] |= pix;
  418.                     rover2 = 0;
  419.                     rover1 = 1;
  420.                     break;
  421.                     }
  422.                 }
  423.                 else if (q == 3)
  424.                 {
  425.                     _Scrn1[i][yoffset + (x >> 4)] |= pix;
  426.                     _Scrn2[i][yoffset + (x >> 4)] |= pix;
  427.                     _Scrn3[i][yoffset + (x >> 4)] |= pix;
  428.                 }
  429.             }
  430.  
  431.  
  432.             /*
  433.              *   get ready for next row by incrementing offset
  434.              *   into the screens (640 dots = 40 words)
  435.              */
  436.             yoffset += 40;
  437.  
  438.  
  439.             /*
  440.              *   exchange error arrays
  441.              */
  442.             TmpErr  = _Err1;
  443.             _Err1   = _Err2;
  444.             _Err2   = TmpErr;
  445.  
  446.  
  447.             /*
  448.              *   check for early withdrawal...
  449.              */
  450.             if (Bconstat (2))
  451.             {
  452.                 while (Bconstat (2))
  453.                     (void) Bconin (2);
  454.                 Setscreen ((long) old1, (long) old2, -1);
  455.                 return;
  456.             }
  457.         }
  458.     }
  459.  
  460.  
  461.  
  462.     /*
  463.      *   now set screen to first image...
  464.      */
  465.     Setscreen (old2, (long) _Scrn, -1); Vsync ();
  466.  
  467.  
  468.  
  469.     /*
  470.      *   with that all done, now we can display the screens. only
  471.      *   phys screen is displayed (at next vblank). the Vsync waits
  472.      *   for the vblank. we display screens 1,2,3. any char stops the
  473.      *   loop.
  474.      *
  475.      *   it goes like this ("screen" is the dithered flicker screen):
  476.      *
  477.      *    frame cmd[0]    screen 1
  478.      *            screen 2
  479.      *            screen 3
  480.      *    frame cmd[1]    screen 1
  481.      *            screen 2
  482.      *            screen 3
  483.      *    ...
  484.      *
  485.      *   show screens at speed. wait for keypress (which ends the loop)...
  486.      */
  487.     done = 0;
  488.     do
  489.     {
  490.         /*
  491.          *   loop over commands. each cmd is a frame number.
  492.          */
  493.         for (i = 0; i < _Ncommands; i++)
  494.         {
  495.             /*
  496.              *   best way to do the delay seems to be display the
  497.              *   same frame in a loop then move to the next. the
  498.              *   trick is to find how long Setscreen/Vsync takes.
  499.              */
  500.             for (j = 0; j < rpt; j++)
  501.             {
  502.                 Setscreen (old2, _Scrn1[cmd[i]], -1); Vsync ();
  503.                 Setscreen (old2, _Scrn2[cmd[i]], -1); Vsync ();
  504.                 Setscreen (old2, _Scrn3[cmd[i]], -1); Vsync ();
  505.             }
  506.             if (Bconstat (2))
  507.             {
  508.                 done = 1;
  509.                 break;
  510.             }
  511.         }
  512.  
  513.     } while (!done);
  514.  
  515.  
  516.  
  517.  
  518.     /*
  519.      *   reset screens back to what they were
  520.      */
  521.     Setscreen ((long) old1, (long) old2, -1);
  522.  
  523.  
  524.  
  525.     /*
  526.      *   clear any waiting keys...
  527.      */
  528.     while (Bconstat (2))
  529.         (void) Bconin (2);
  530. }
  531.  
  532.  
  533.  
  534.  
  535. /*------------------------------*/
  536. /*    _SimpConv2Gray        */
  537. /*------------------------------*/
  538. static void _SimpConv2Gray (unsigned char *pic, int *cmd)
  539. {
  540.  
  541. /*
  542.  *    I have also made a version of "Convert2Gray", that don't use
  543.  *    flicker - this allows the pictures to be saved, and used in windows,
  544.  *    and honest - the build-in test-picture looks as good, or even better, 
  545.  *    without the flicker... (this is not true for any *real* pictures 
  546.  *    that I have tested the program with). Here it is :
  547.  */
  548.  
  549.     unsigned char  *ppic;
  550.     int        i;
  551.     int        j;
  552.     long        x,
  553.             y,
  554.             yoffset,
  555.             wordpos;
  556.     I16        w,
  557.             h;
  558.     I16           *TmpErr;
  559.     UI16        pix;
  560.     unsigned char  *p;
  561.     char           *old1;
  562.     char           *old2;
  563.     int        rpt;
  564.     int        done;
  565.  
  566.  
  567.  
  568.     /*
  569.      *   15 ms for one Setscreen/Vsync is about right on 8MHz
  570.      *   ST...
  571.      */
  572.     rpt = _Delay / 15;
  573.  
  574.  
  575.  
  576.     /*
  577.      *   save old screen info
  578.      */
  579.     old1  = (char *) Logbase ();
  580.     old2  = (char *) Physbase ();
  581.  
  582.  
  583.  
  584.     /*
  585.      *   clear...
  586.      */
  587.     if (_Show)
  588.         printf ("flicker: clear screen...\n");
  589.     bzero (old1, (size_t) 32000);
  590.     bzero (old2, (size_t) 32000);
  591.  
  592.  
  593.  
  594.     /*
  595.      *   there is only one screen. we use existing physbase
  596.      */
  597.     _Scrn1[0] = _Scrn;
  598.     for (i = 1; i < _Nframes; i++)
  599.     {
  600.         _Scrn1[i] = _Scrn1[i-1] + 16000L;
  601.     }
  602.  
  603.  
  604.  
  605.     /*
  606.      *   we have to dither each frame so be patient...
  607.      */
  608.     for (ppic = pic, i = 0; i < _Nframes; i++, ppic += _Hight*_Width)
  609.     {
  610.         /*
  611.          *   monitor the progress of dithering.
  612.          *   set logbase to old physbase and physbase to first
  613.          *   screen buffer. we *should* never see logbase in the
  614.          *   displayed image since we never display logbase.
  615.          */
  616.         Setscreen (old2, (long) _Scrn1[i], -1); Vsync ();
  617.  
  618.  
  619.  
  620.         /*
  621.          *   first clear the error arrays
  622.          */
  623.         _ClearErr ();
  624.  
  625.  
  626.         /*
  627.          *   yoffset positions us into the screen which is an int
  628.          *   arrays.each scan line in the screen is thus 40 words
  629.          *   long.
  630.          */
  631.         yoffset = 0;
  632.         pix     = 0;
  633.  
  634.  
  635.         /*
  636.          *   loop over all rows in image
  637.          */
  638.         h = (_Hight > 400) ? 400 : _Hight;
  639.         for (y = 1; y < h - 1; y++)
  640.         {
  641.             /*
  642.              *   set ptr to this pixel row
  643.              */
  644.             p       = ppic + ((long) y * (long) _Width);
  645.             wordpos = yoffset;
  646.  
  647.  
  648.             /*
  649.              *   loop over all pixels in the row
  650.              */
  651.             w = (_Width > 640) ? 640 : _Width;
  652.             for (x = 0L; x < w; x++)
  653.             {
  654.                 pix <<= 1;
  655.                 if (_SimpGenConvPix (p, (int) x, 0))
  656.                     pix++;
  657.                 if ((x & 0x0f) == 0x0f)
  658.                     _Scrn1[i][wordpos++] = pix;
  659.             }
  660.  
  661.  
  662.             /*
  663.              *   clean up last word if any
  664.              */
  665.             if (w % 16)
  666.             {
  667.                 int    shft;
  668.  
  669.                 shft              = 16 - (w % 16);
  670.                 pix             <<= shft;
  671.                 _Scrn1[i][wordpos++] = pix;
  672.             }
  673.  
  674.  
  675.             /*
  676.              *   get ready for next row by incrementing offset
  677.              *   into the screens (640 dots = 40 words)
  678.              */
  679.             yoffset += 40;
  680.  
  681.  
  682.             /*
  683.              *   exchange error arrays
  684.              */
  685.             TmpErr  = _Err1;
  686.             _Err1   = _Err2;
  687.             _Err2   = TmpErr;
  688.  
  689.  
  690.             /*
  691.              *   check for early withdrawal...
  692.              */
  693.             if (Bconstat (2))
  694.             {
  695.                 while (Bconstat (2))
  696.                     (void) Bconin (2);
  697.                 Setscreen ((long) old1, (long) old2, -1);
  698.                 return;
  699.             }
  700.         }
  701.     }
  702.  
  703.  
  704.  
  705.     /*
  706.      *   now set screen to first image...
  707.      */
  708.     Setscreen (old2, (long) _Scrn, -1); Vsync ();
  709.  
  710.  
  711.  
  712.     /*
  713.      *    do it...
  714.      */
  715.     done = 0;
  716.     do
  717.     {
  718.         /*
  719.          *   loop over commands. each cmd is a frame number.
  720.          */
  721.         for (i = 0; i < _Ncommands; i++)
  722.         {
  723.             /*
  724.              *   the best way to do the delay seems to display the
  725.              *   same frame in a loop then move to the next. the
  726.              *   trick is to find how long a Setscreen/Vsync
  727.              *   takes.
  728.              */
  729.             for (j = 0; j < rpt; j++)
  730.             {
  731.                 Setscreen (old2, _Scrn1[cmd[i]], -1); Vsync ();
  732.             }
  733.             if (Bconstat (2))
  734.             {
  735.                 done = 1;
  736.                 break;
  737.             }
  738.         }
  739.  
  740.     } while (!done);
  741.  
  742.  
  743.  
  744.     /*
  745.      *   reset screens back to what they were
  746.      */
  747.     Setscreen ((long) old1, (long) old2, -1);
  748.  
  749.  
  750.  
  751.     /*
  752.      *   clear any waiting keys...
  753.      */
  754.     while (Bconstat (2))
  755.         (void) Bconin (2);
  756. }
  757.  
  758.  
  759.  
  760.  
  761. /*------------------------------*/
  762. /*    _GenConvPix        */
  763. /*------------------------------*/
  764. static I16 _GenConvPix (unsigned char *pic, int x, int opt)
  765.  
  766.         /* pic        -> image pixel array */
  767.         /* x        the current pixel */
  768.         /* opt        0=l to r, 1=r to l */
  769. {
  770.  
  771. /*
  772.  *    This routine converts a point in the 'real' image to
  773.  *    a point in the screen image. The procedure uses error-
  774.  *    diffusion to determine the state of the new pixel.
  775.  *    The Error filter is that of Floyd & Steinberg :
  776.  *
  777.  *        / 1  5  3 \  / 
  778.  *        \ 7  X    / / 16
  779.  *
  780.  *    This rutine uses a table of levels to make the convertion.
  781.  *
  782.  *    It returns the index for the pixel from the quantizing Level
  783.  *    array, i.e. the new pixel intensity is Level[i].
  784.  */
  785.  
  786.     register I16   *p_levels;
  787.     register I16    p;
  788.     register I16    e;
  789.     register I16    i;
  790.     register I16    err;
  791.     I16        lev = 0;
  792.  
  793.  
  794.     p_levels = _Levels;
  795.  
  796.  
  797. #ifdef NEW_RANDOM
  798. /*
  799.     The noise is here added to the picture, this means that the noise
  800.     isn't cancled out again, and that is NOT intended, the noise should
  801.     only act as some kind of *catalysator* (verb. is stolen from 
  802.     chemistry - something that start a reaction).
  803. */
  804.  
  805.     /*
  806.      *   first do the weighted average. _Err1 is the current line,
  807.      *   _Err2 is the previous line.
  808.      */
  809.     if (x == 0)
  810.     {
  811. # ifdef NO_INVERT
  812.         /*!!! next line was actually: */
  813.  
  814.         p = *pic;
  815.  
  816.         /*!!! but that inverted the image. it was assumed that 0xff
  817.               was black. we insist that black is 0x00 (low intensity)*/
  818. # else /*!NO_INVERT*/
  819.         p = 255 - *pic;
  820. # endif /*NO_INVERT*/
  821.     }
  822.     else if (_Beta)
  823.     {
  824.         p = ((7*_Err1[x - 1]
  825.               + _Err2[x - 1] + 5*_Err2[x] + 3*_Err2[x + 1]) >> 4)
  826.               + _Laplace (pic + x);
  827.     }
  828.     else
  829.     {
  830.         p = ((7*_Err1[x - 1]
  831.               + _Err2[x - 1] + 5*_Err2[x] + 3*_Err2[x + 1]) >> 4)
  832. # ifdef NO_INVERT
  833.               + *(pic + x);
  834. # else /*!NO_INVERT*/
  835.               + (255 - *(pic + x));
  836. # endif /*NO_INVERT*/
  837.     }
  838.  
  839.  
  840.     /*
  841.      *   now calculate the residual errors
  842.      */
  843.     err = NUMERRS;
  844.     for (i = 0; i < LEVELS; i++)
  845.     {
  846.         if (_MaxRandom)
  847.             e = p + _Rand (_MaxRandom) - p_levels[i];
  848.         else
  849.             e = p - p_levels[i];
  850.  
  851.         if (e < 0)
  852.             e = -e;
  853.         if (e < err)
  854.         {
  855.             err = e;
  856.             lev = (I16) i;
  857.         }
  858.     }
  859.     _Err1[x] = p - p_levels[lev];
  860.  
  861. #else /*!NEW_RANDOM*/
  862.  
  863.     if (x == 0)
  864.     {
  865. # ifdef NO_INVERT
  866.         p = *pic;
  867. # else /*!NO_INVERT*/
  868.         p = 255 - *pic;
  869. # endif /*NO_INVERT*/
  870.     }
  871.     else if (_Beta)
  872.     {
  873.         if (_MaxRandom)
  874.             p = ((7 * _Err1[x - 1] + _Err2[x - 1]
  875.                 + 5 * _Err2[x] + 3 * _Err2[x + 1]) >> 4)
  876.                 + _Laplace (pic + x) + _Rand (_MaxRandom);
  877.         else
  878.             p = ((7 * _Err1[x - 1] + _Err2[x - 1]
  879.                 + 5 * _Err2[x] + 3 * _Err2[x + 1]) >> 4)
  880.                 + _Laplace (pic + x);
  881.     }
  882.     else
  883.     {
  884.         if (_MaxRandom)
  885.         {
  886.             p = ((7 * _Err1[x - 1] + _Err2[x - 1]
  887.                 + 5 * _Err2[x] + 3 * _Err2[x + 1]) >> 4)
  888. # ifdef NO_INVERT
  889.                 + *(pic + x) + _Rand (_MaxRandom);
  890. # else /*!NO_INVERT*/
  891.                 + (255 - *(pic + x)) + _Rand (_MaxRandom);
  892. # endif /*NO_INVERT*/
  893.         }
  894.         else
  895.         {
  896.             p = ((7 * _Err1[x - 1] + _Err2[x - 1]
  897.                 + 5 * _Err2[x] + 3 * _Err2[x + 1]) >> 4)
  898. # ifdef NO_INVERT
  899.                 + *(pic + x);
  900. # else /*!NO_INVERT*/
  901.                 + (255 - *(pic + x));
  902. # endif /*NO_INVERT*/
  903.         }
  904.     }
  905.     err = NUMERRS;
  906.     for (i = 0; i < LEVELS; i++)
  907.     {
  908.         e = p - p_levels[i];
  909.         if (e < 0)
  910.             e = -e;
  911.         if (e < err)
  912.         {
  913.             err = e;
  914.             lev = (I16) i;
  915.         }
  916.     }
  917.     _Err1[x] = p - p_levels[lev];
  918.  
  919. #endif /*NEW_RANDOM*/
  920.  
  921.     return (lev);
  922. }
  923.  
  924.  
  925.  
  926.  
  927. /*------------------------------*/
  928. /*    _SimpGenConvPix        */
  929. /*------------------------------*/
  930. static I16 _SimpGenConvPix (unsigned char *pic, int x, int opt)
  931.  
  932.         /* pic        -> image pixel array */
  933.         /* x        the current pixel */
  934.         /* opt        0=l to r, 1=r to l */
  935. {
  936.  
  937. /*
  938.  *    This version is for SimpConv2Gray. no laplace, no noise...
  939.  *
  940.  *    This rutine converts a point in the 'real' image to
  941.  *    a point in the screen image. The procedure uses error-
  942.  *    diffusion to determine the state of the new pixel.
  943.  *    The Error filter is that of Floyd & Steinberg :
  944.  *
  945.  *        / 1  5  3 \  / 
  946.  *        \ 7  X    / / 16
  947.  *
  948.  *    This rutine uses a table of levels to make the convertion.
  949.  *
  950.  *    It returns the index for the pixel from the quantizing Level
  951.  *    array, i.e. the new pixel intensity is Level[i].
  952.  */
  953.  
  954.     register I16   *p_levels;
  955.     register I16    p;
  956.     register I16    e;
  957.     register I16    i;
  958.     register I16    err;
  959.     I16        lev = 0;
  960.  
  961.  
  962.     p_levels = _SimpLevels;
  963.  
  964.  
  965.     /*
  966.      *   first do the weighted average. _Err1 is the current line,
  967.      *   _Err2 is the previous line.
  968.      */
  969.     if (x == 0)
  970.     {
  971. # ifdef NO_INVERT
  972.         /*!!! next line was actually: */
  973.  
  974.         p = *pic;
  975.  
  976.         /*!!! but that inverted the image. it was assumed that 0xff
  977.               was black. we insist that black is 0x00 (low intensity)*/
  978. # else
  979.         p = 255 - *pic;
  980. # endif
  981.     }
  982.     else
  983.     {
  984. # ifdef NO_INVERT
  985.         p = ((7*_Err1[x - 1]
  986.               + _Err2[x - 1] + 5*_Err2[x] + 3*_Err2[x + 1]) >> 4)
  987.               + *(pic + x);
  988. # else
  989.         p = ((7*_Err1[x - 1]
  990.               + _Err2[x - 1] + 5*_Err2[x] + 3*_Err2[x + 1]) >> 4)
  991.               + (255 - *(pic + x));
  992. # endif
  993.     }
  994.  
  995.  
  996.     /*
  997.      *   now calculate the residual errors
  998.      */
  999.     err = NUMERRS;
  1000.     for (i = 0; i < 2; i++)
  1001.     {
  1002.         e = p - p_levels[i];
  1003.  
  1004.         if (e < 0)
  1005.             e = -e;
  1006.         if (e < err)
  1007.         {
  1008.             err = e;
  1009.             lev = i;
  1010.         }
  1011.     }
  1012.     _Err1[x] = p - p_levels[lev];
  1013.  
  1014.     return (lev);
  1015. }
  1016.  
  1017.  
  1018.  
  1019.  
  1020. /*------------------------------*/
  1021. /*    _Laplace        */
  1022. /*------------------------------*/
  1023. static I16 _Laplace (unsigned char *Pic)
  1024. {
  1025.  
  1026. /*
  1027.  *    this is a Laplacian filter, a simple edge detector/enhancer.
  1028.  *
  1029.  *           -1
  1030.  *        -1  4 -1
  1031.  *           -1
  1032.  */
  1033.  
  1034.     register unsigned char *pc;
  1035.     register I16        lp;
  1036.     register I16        b;
  1037.     register I16        w;
  1038.  
  1039.  
  1040.     pc = Pic;
  1041.     b  = _Beta;
  1042.     w  = _Width;
  1043.  
  1044.  
  1045.  
  1046.     /*
  1047.      *   if _Beta 0, formula reduces to just the pixel
  1048.      */
  1049. #ifdef NO_INVERT
  1050.     if (b == 0)
  1051.         return ((I16) *pc);
  1052.  
  1053.     lp = (*pc << 2)                /* this pixel */
  1054.        - *(pc - 1) - *(pc + 1)        /* left/right */
  1055.        - *(pc + w) - *(pc - w);        /* top/bottom */
  1056.     lp = ((b * lp) >> 2) + *pc;
  1057. #else /*!NO_INVERT*/
  1058.     if (b == 0)
  1059.         return ((I16) (255 - *pc));
  1060.  
  1061.     lp  = (255 - *pc) << 2;            /* this pixel */
  1062.     lp -= (255 - *(pc - 1));        /* left/right */
  1063.     lp -= (255 - *(pc + 1));
  1064.     lp -= (255 - *(pc + w));        /* top/bottom */
  1065.     lp -= (255 - *(pc - w));
  1066.     lp  = ((b * lp) >> 2);
  1067.     lp += (255 - *pc);            /* self */
  1068. #endif /*NO_INVERT*/
  1069.  
  1070.     /*
  1071.      *   check limits and force result to 8 bits
  1072.      */
  1073.     if (lp < 0)
  1074.         lp = 0;
  1075.     if (lp > 255)
  1076.         lp = 255;
  1077.  
  1078.     return (lp);
  1079. }
  1080.  
  1081.  
  1082.  
  1083.  
  1084. /*------------------------------*/
  1085. /*    _ClearErr        */
  1086. /*------------------------------*/
  1087. static void _ClearErr (void)
  1088. {
  1089.     register int    i;
  1090.     register I16    w;
  1091.     register I16   *pe1;
  1092.     register I16   *pe2;
  1093.  
  1094.  
  1095.     _Err1 = _Err1Array;
  1096.     _Err2 = _Err2Array;
  1097.  
  1098.     pe1   = _Err1Array;
  1099.     pe2   = _Err2Array;
  1100.     w     = _Width;
  1101.     for (i = 0; i < w; i++)
  1102.     {
  1103.         *pe1++ = 0;
  1104.         *pe2++ = 0;
  1105.     }
  1106. }
  1107.  
  1108.  
  1109.  
  1110.  
  1111. /*------------------------------*/
  1112. /*    _Rand            */
  1113. /*------------------------------*/
  1114. static I16 _Rand (I16 mx)
  1115. {
  1116.  
  1117. /*
  1118.  *    returns random number 0 <= x < mx. no real need to initialize this.
  1119.  */
  1120.  
  1121.     static long     Seed = 0;
  1122.  
  1123.     if (mx == 0)
  1124.         return (0);
  1125.  
  1126.     Seed += (Seed << 2) + 37;
  1127. /*    Seed &= 0x00007fffL;*/            /* should prevent overflow */
  1128.  
  1129.     return (((I16) Seed) % mx);
  1130. }
  1131.  
  1132.